import { Module, OnModuleInit } from '@nestjs/common';
import { TypeOrmModule, TypeOrmModuleOptions } from '@nestjs/typeorm';
import { CacheInterceptor, CacheModule } from '@nestjs/cache-manager';
import { redisStore } from 'cache-manager-redis-yet';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { UserModule } from './user/user.module';
import { User } from './user/entities/user.entity';
import { FileModule } from './file/file.module';
import { APP_GUARD, APP_INTERCEPTOR } from '@nestjs/core';
import { JwtAuthGuard } from './common/guards/JwtGuard';
import { SmsCaptchaModule } from './sms-captcha/sms-captcha.module';
import { AclAuthGuard } from './common/guards/AclGuard';
import { ThrottlerGuard, ThrottlerModule } from '@nestjs/throttler';
import { ConfigModule } from '@nestjs/config';
import { AuthModule } from './auth/auth.module';
import { FileService } from './file/file.service';
import { CronExpression } from '@nestjs/schedule';
import { SchedulerModule } from './scheduler/scheduler.module';
import { NotifyModule } from './notify/notify.module';
import { SchedulerService } from './scheduler/scheduler.service';
import { BullModule } from '@nestjs/bull';

// 从环境变量里获取mysql、redis配置
const getConfig = (env: any, type: string): TypeOrmModuleOptions | any => {
  if ('mysql' === type) {
    return {
      type: 'mysql', //数据库类型
      username: env.DB_NAME,
      password: env.DB_PWD,
      host: env.DB_HOST,
      port: env.DB_PORT,
      database: env.DB_TABLE,
      entities: ['dist/**/*.entity{.ts,.js}'], //实体文件
      synchronize: false, //synchronize字段代表是否自动将实体类同步到数据库
      retryDelay: 500, //重试连接数据库间隔
      retryAttempts: 10, //重试连接数据库的次数
      autoLoadEntities: true, //如果为true,将自动加载实体 forFeature()方法注册的每个实体都将自动添加到配置对象的实体数组中
      timezone: '+08:00', // 时区东八区
    };
  } else if ('redis' === type) {
    const dbObj = 'development' === env.NODE_ENV ? { database: 2 } : {}; // db参数不生效，改用database
    return {
      isGlobal: true,
      store: redisStore,
      host: env.REDIS_HOST,
      port: env.REDIS_PORT,
      password: env.REDIS_PWD,
      ttl: 5, // 缓存的默认过期时间是5秒，他会缓存api接口 （@4中是秒，@5中是毫秒）
      ...dbObj,
    };
  }else if('queue' === type) {
    return {
      redis: {
        host: env.REDIS_HOST,
        port: env.REDIS_PORT,
        password: env.REDIS_PWD,
      },
      defaultJobOptions: {
        removeOnComplete: true, // 任务完成时移除队列
        removeOnFail: true,     // 任务失败时移除队列
      }
    }
  }
};

@Module({
  imports: [
    ConfigModule.forRoot({
      isGlobal: true,
      envFilePath: [`.env.${process.env.NODE_ENV || 'production'}`],
    }),
    TypeOrmModule.forRoot(getConfig(process.env, 'mysql')), // 连接MySQL
    CacheModule.register(getConfig(process.env, 'redis')),  // 连接Redis
    BullModule.forRoot(getConfig(process.env, 'queue')),    // 队列设置
    ThrottlerModule.forRoot([{ ttl: 60, limit: 60 }]),      // ttl：秒，60秒限制60个请求
    TypeOrmModule.forFeature([User]), // 注册后才能在service中使用
    UserModule,
    FileModule,
    SmsCaptchaModule,
    AuthModule,
    SchedulerModule,
    NotifyModule,
  ],
  controllers: [AppController],
  providers: [
    AppService,
    { provide: APP_GUARD, useClass: ThrottlerGuard },
    { provide: APP_INTERCEPTOR, useClass: CacheInterceptor },
    { provide: APP_GUARD, useClass: JwtAuthGuard },
    { provide: APP_GUARD, useClass: AclAuthGuard },
  ],
  exports: [AppService],
})
export class AppModule implements OnModuleInit {
  constructor(
    private fileService: FileService,
    private schedulerService: SchedulerService,
  ) {}

  /*
        应用启动后需要执行的逻辑，比如重启定时任务
        新建定时任务时，需要把任务的数据放到数据库里，定时任务完成时清除对应数据，这样可以保证服务重启后任务依旧还会执行
        队列不用入库，因为redis有本地缓存
    */
  async onModuleInit() {
    // 每天0点执行任务
    this.fileService.addJob( { name: 'clean_file' }, CronExpression.EVERY_DAY_AT_4AM );

    // 重启定时任务
    const schedulers = await this.schedulerService.findAll();
    // MJ、绘图、视频查询任务，服务启动后按照指定时间执行
    schedulers.forEach((item) => {});
  }
}
